package org.six11.ss.server;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import javax.imageio.ImageIO;

import com.lowagie.text.DocumentException;
import com.lowagie.text.FontFactory;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.DefaultFontMapper;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfTemplate;
import com.lowagie.text.pdf.PdfWriter;

import org.hibernate.Transaction;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.six11.ss.client.olive.BasicRenderer;
import org.six11.ss.client.olive.OliveState;
import org.six11.ss.server.bean.Sketch;
import org.six11.ss.shared.Message;
import org.six11.util.adt.MultiState;
import org.six11.util.gui.Components;
import org.six11.util.pen.Pt;

/**
 * 
 * 
 * @author Gabe Johnson <johnsogg@cmu.edu>
 */
public class ImageUtil {
  public static String TYPE_PDF = "pdf";
  public static String TYPE_PNG = "png";

  public static int DEFAULT_WIDTH = 400;
  public static int DEFAULT_HEIGHT = 400;

  private ImageBroker servlet;
  private BasicRenderer renderer;
  private OliveState oliveState;

  public ImageUtil(ImageBroker broker) {
    this.servlet = broker;
    this.renderer = new BasicRenderer();
    MultiState programState = new MultiState();
    this.oliveState = new OliveState(programState);
  }

  /**
   * @param id
   * @param type
   */
  public void generateImage(int id, String type) {
    generateImage(id, type, DEFAULT_WIDTH, DEFAULT_HEIGHT);
  }

  public void generateImage(int id, String type, int w, int h) {
    String typeStr = "";
    if (type.contains(TYPE_PDF)) {
      typeStr = ".pdf";
    } else if (type.contains(TYPE_PNG)) {
      typeStr = ".png";
    }
    generateImage(id, type, w, h, new File(servlet.getBaseDir(), id + typeStr));
  }

  @SuppressWarnings("unchecked")
  public void generateImage(int id, String type, int w, int h, File f) {
    Message sketchMessage = null;
    Transaction tx = servlet.getHibernate().beginTransaction();
    try {
      Sketch sketch = servlet.loadSketch(id + "");
      String data = sketch.getData();
      try {
        sketchMessage = Message.fromXml(data);
        List<Element> dataz = sketchMessage.getRoot().getChildren("pen_data");
        for (Element elm : dataz) {
          Pt pt = new Pt(Integer.parseInt(elm.getAttributeValue("x")), Integer.parseInt(elm
              .getAttributeValue("y")));
          String who = elm.getAttributeValue("personID");
          String penAction = elm.getAttributeValue("type");
          if (penAction.equals("down")) {
            oliveState.addForeignSequenceBegin(pt, who);
          } else if (penAction.equals("up")) {
            oliveState.addForeignSequenceEnd(pt, who);
          } else if (penAction.equals("move")) {
            oliveState.addForeignSequenceProgress(pt, who);
          } else {
            // huh? unknown pen action
          }
        }
      } catch (JDOMException ex) {
        ex.printStackTrace();
      }
    } catch (Exception ex) {
      ex.printStackTrace();
    } finally {
      tx.commit();
    }

    if (type.contains(TYPE_PDF)) {
      generatePdf(f);
    }
    if (type.contains(TYPE_PNG)) {
      generatePng(f, w, h);
    }
  }

  public void generatePdf(File file) {
    int w = DEFAULT_WIDTH;
    int h = DEFAULT_HEIGHT;
    Rectangle size = new Rectangle(w, h);
    com.lowagie.text.Document document = new com.lowagie.text.Document(size, 0, 0, 0, 0);

    try {
      PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
      document.open();

      DefaultFontMapper mapper = new DefaultFontMapper();
      FontFactory.registerDirectories();

      PdfContentByte cb = writer.getDirectContent();
      PdfTemplate tp = cb.createTemplate(w, h);
      Graphics2D g2 = tp.createGraphics(w, h, mapper);
      tp.setWidth(w);
      tp.setHeight(h);
      renderer.renderSequences(g2, oliveState.getSequences());

      g2.dispose();
      cb.addTemplate(tp, 0, 0);
    } catch (DocumentException ex) {
      System.err.println(ex.getMessage());
    } catch (IOException ex) {
      System.err.println(ex.getMessage());
    }
    document.close();
    oliveState.clearSurface();
  }

  public void generatePng(File file) {
    generatePng(file, DEFAULT_WIDTH, DEFAULT_HEIGHT);
  }

  public void generatePng(File file, int w, int h) {
    BufferedImage bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2 = bufferedImage.createGraphics();
    Components.antialias(g2);
    double xs = ((double) w) / ((double) DEFAULT_WIDTH);
    double ys = ((double) h) / ((double) DEFAULT_HEIGHT);
    g2.scale(xs, ys);
    renderer.renderSequences(g2, oliveState.getSequences());
    g2.dispose();
    try {
      ImageIO.write(bufferedImage, "png", file);
    } catch (IOException ex) {
      System.err.println(ex.getMessage());
    }
    oliveState.clearSurface();
  }

}
